home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <nslib.h>
- #include "pc_inc.h"
-
- #define EOS (256)
-
-
- static void count( char *src, NODE *node, int n )
- {
- int i;
- unsigned int max=0;
-
- _fill_b( node, 0, sizeof( NODE )*514 );
-
- for( i=0; i<n; i++ )
- node[src[i]].cu++;
-
- for( i=0; i<256; i++ )
- if ( node[i].cu > max )
- max = node[i].cu;
-
- for( i=0; i<256; i++ )
- if ( node[i].cu )
- {
- node[i].cu = ( node[i].cu * 255 ) / max;
- if ( node[i].cu == 0 ) node[i].cu++;
- }
- node[EOS].cu = 1;
- }
-
- static int eq( NODE *node, int n )
- {
- int i;
- for( i=1; i<n; i++ ) if ( node[0].cu != node[i].cu ) return ( i );
- return ( n );
- }
-
- static int movs( char *dest, NODE *node, int *n )
- {
- int i, m=127;
-
- if ( *n > 127 )
- { dest[0] = 127; *n -= 127; }
- else
- { dest[0] = (schar)(*n); m = *n; *n = 0; }
-
- for( i=0; i<m; i++ )
- dest[i+1] = (char)node[i].cu;
- return ( m+1 );
- }
-
- static int putcount( NODE *node, BIT_FILE *bfp )
- {
- int i, edi=0, cu=0, eqn=0;
- char buf[512];
-
- for( i=0; i<256; )
- {
- if ( ( eqn = eq( &node[i], 256-i ) ) > 2 )
- {
- while( cu )
- edi += movs( &buf[edi], &node[i-cu], &cu );
- if ( eqn > 128 )
- eqn = 128;
- buf[edi++] = -(schar)eqn;
- buf[edi++] = node[i].cu;
- }
- else
- cu += eqn;
- i += eqn;
- }
-
- while( cu )
- edi += movs( &buf[edi], &node[i-cu], &cu );
- if ( BIT_write_bytes( buf, edi, 1, bfp ) < 1 )
- return (-1);
-
- return ( edi );
- }
-
- static int getcount( NODE *node, BIT_FILE *bfp )
- {
- int i;
- schar c, si;
- char d, buf[256];
-
- for( i=0; i<256; )
- {
- if ( BIT_read_bytes( &c, 1, 1, bfp ) < 1 )
- return (-1);
- if ( c < 0 )
- {
- if ( BIT_read_bytes( &d, 1, 1, bfp ) < 1 )
- return (-1);
- for( ; c; c++, i++ )
- node[i].cu = (int)d;
- }
- else
- {
- if ( BIT_read_bytes( buf, (int)c, 1, bfp ) < 1 )
- return (-1);
- for( si=0; si<c; si++, i++ )
- node[i].cu = (int)buf[si];
- }
- }
- node[EOS].cu = 1;
- return (0);
- }
-
- static int tree_for_encode( NODE *node )
- {
- int next, i, min1, min2;
-
- for( i=0; i<256; i++ )
- if ( node[i].cu == 0 )
- node[i].c0 = i;
-
- node[513].cu = 0xffffffff;
- for( next=EOS+1; ; next++ )
- {
- min1 = min2 = 513;
- for( i=0; i<next; i++ )
- if ( node[i].cu )
- if ( node[i].cu < node[min1].cu )
- {
- min2 = min1;
- min1 = i;
- }
- else if ( node[i].cu < node[min2].cu )
- min2 = i;
- if ( min2 == 513 )
- break;
- node[next].cu = node[min1].cu + node[min2].cu;
- node[min1].cu = node[min2].cu = 0;
- node[min1].c0 = node[min2].c0 = next;
- node[min1].c1 = 0;
- node[min2].c1 = 1;
- }
- next--;
- node[next].c0 = next;
- return ( next );
- }
-
- static int tree_for_decode( NODE *node )
- {
- int next, i, min1, min2;
-
- node[513].cu = 0xffffffff;
- for( next=EOS+1; ; next++ )
- {
- min1 = min2 = 513;
- for( i=0; i<next; i++ )
- if ( node[i].cu )
- if ( node[i].cu < node[min1].cu )
- {
- min2 = min1;
- min1 = i;
- }
- else if ( node[i].cu < node[min2].cu )
- min2 = i;
- if ( min2 == 513 )
- break;
- node[next].cu = node[min1].cu + node[min2].cu;
- node[min1].cu = node[min2].cu = 0;
- node[next].c0 = min1;
- node[next].c1 = min2;
- }
- return ( next-1 );
- }
-
- static void to_code( NODE *node, CODE *code )
- {
- int i, cur, bcu;
-
- _fill_b( code, 0, sizeof( CODE )*257 );
- for( i=0; i<257; i++ )
- {
- for( cur=i, bcu=0; node[cur].c0 != cur; cur=node[cur].c0, bcu++ )
- if ( node[cur].c1 )
- code[i].code |= 1<<bcu;
- code[i].bits = bcu;
- }
- }
-
- static int encode( char *src, int n, BIT_FILE *bfp, CODE *code )
- {
- int i, cu=0;
- unsigned int bits;
-
- for( i=0; i<n; i++ )
- {
- bits = code[src[i]].bits;
- if ( BIT_write_bits( code[src[i]].code, bits, bfp ) < bits )
- return (-1);
- cu += bits;
- }
- bits = code[EOS].bits;
- if ( BIT_write_bits( code[EOS].code, bits, bfp ) < bits )
- return (-1);
- cu += bits;
-
- return ( cu );
- }
-
- static int decode( char *dest, BIT_FILE *bfp, NODE *node, int root )
- {
- int i, nd;
- unsigned int buf;
-
- for( i=0; ; i++ )
- {
- nd = root;
- do {
- if ( BIT_read_bit( &buf, bfp ) == 0 )
- return (i);
- if ( buf )
- nd = node[nd].c1;
- else
- nd = node[nd].c0;
- }
- while( nd > EOS );
- if ( nd == EOS ) break;
- dest[i] = (char)nd;
- }
- return (i);
- }
-
- int huff_comp( char *src, int n, BIT_FILE *bfp )
- {
- NODE node[514];
- CODE code[257];
- int bytes, ret;
-
- count( src, node, n );
- if ( ( bytes = putcount( node, bfp ) ) == -1 )
- return (-1);
- tree_for_encode( node );
- to_code( node, code );
- if ( ( ret = encode( src, n, bfp, code ) ) == -1 )
- return (-1);
- return ( bytes + (ret+7)/8 );
- }
-
- int huff_exp( char *dest, BIT_FILE *bfp )
- {
- NODE node[514];
- int root;
-
- if ( getcount( node, bfp ) == -1 )
- return (-1);
- root = tree_for_decode( node );
- return ( decode( dest, bfp, node, root ) );
- }
-